43  数据结构之列表

本章定位(复习与补充训练层):本章对应正课第2章《列表、字典和元组》(章节 2)的列表部分,并与第37章《数据基本结构(元组、列表、字典)》(章节 38)互为补充训练(本章为分项版),用于复习、补缺与额外练习。建议先不看讲解,直接尝试下方平台任务,再对照解析补弱项。本章不属于必修主线。先做本章『动手与思考』第 1 题与平台任务自测,通过即可跳过本章。

43.1 引言列表在数据管理中的核心地位

列表(List)是有序、可变、支持异构元素的通用序列,既能实时更新价格,也能增量采集数据。本章用一个含四个小任务的平台代码块,检验你对列表索引访问、追加、增删与排序的复习效果。

43.2 本章学习目标

本章为复习与补充训练,目标是检验你是否能脱离正课独立完成下列任务:

  1. 能独立完成平台任务一:创建指数名称列表 name_index 与收盘点数列表 price_index,用 name_index[2] 访问指定元素、用 price_index.index(8376.63) 查找元素的索引值
  2. 能独立完成平台任务二:用 append() 向两个列表末尾追加新指数名称与点数
  3. 能独立完成平台任务三:用 remove() 删除指定点数、用 insert(6, 2674.45) 在指定索引处插入新数据,并解释任务三后两个列表为何会错位
  4. 能独立完成平台任务四:用 sort() 升序排序、reverse() 反转、clear() 清空列表
  5. 能说出 sort()sorted()append()insert() 的区别,以及常用列表操作的时间复杂度

若上述任务无法独立完成,请回到正课第2章列表部分补弱,再回到本章练习。

43.3 列表的基本操作

先用一张表概括列表的四大核心特性,后续所有操作都围绕它们展开:

列表的四大核心特性:

特性 技术实现 时间复杂度 金融应用场景
可变性 元素可直接修改 O(1) 实时价格更新
有序性 维护插入顺序 - 时间序列数据
异构性 存储任意类型对象 - 混合数据记录
动态性 自动扩容 amortized O(1) 增量数据采集

平台任务(平台原始代码)

以下代码与教学平台任务要求完全一致:

任务要求(单块含任务一至任务四):给定指数名称列表 name_index 与收盘点数列表 price_index(各7个元素、按下标一一对应)。 - 任务一:用 name_index[2] 访问指定元素,用 price_index.index(8376.63) 查找该点数所在的索引值并输出; - 任务二:用 append() 分别向两个列表末尾追加4个新指数名称与点数,并输出追加后的列表; - 任务三:用 remove() 删除指定点数、用 insert(6, 2674.45) 在索引6插入新点数,输出两个列表并观察对应关系; - 任务四:依次对 price_index 执行 sort() 升序排序、reverse() 反转、clear() 清空,每步输出。 请按平台原始题面原样输入(注释除外),判定以平台为准。

列表 43.1: 平台原始代码 (1)-(4)
# 注:平台题面为填空形式,下方展示的是填空完成后的参考形态;请按平台原始题面原样输入,以平台判定为准
# 注:平台任务以平台题面为准,以下为任务一至任务四的原始代码
# ⚠️ 平台原始代码 - 请原样输入至教学平台(注释除外),平台才会判定答案正确
#任务一
name_index = ["道琼斯工业平均指数","富时100指数","标普500指数","恒生指数","日经225指数","上证指数","深证指数"]  #创建指数名称列的列表
price_index = [41563.08,8376.63,5648.40,17989.07,38647.75,2842.21,8348.48]  # 定义列表price_index
 
print(name_index[2])        #访问 "标普500指数" 这个元素
 
print(price_index.index(8376.63))       #找出 8376.63 这个元素所在的索引值

#任务二
name_index = ["道琼斯工业平均指数","富时100指数","标普500指数","恒生指数","日经225指数","上证指数","深证指数"] 
price_index = [41563.08,8376.63,5648.40,17989.07,38647.75,2842.21,8348.48]  # 定义列表price_index
 
name_index.append("法国CAC40指数")         #按要求添加新元素
name_index.append("德国DAX指数")  # 将股指名称添加到列表
name_index.append("新加坡海峡指数")  # 将股指名称添加到列表
name_index.append("台湾加权指数")  # 将股指名称添加到列表
print(name_index)                   #打印添加新元素后的name_index列表
 
price_index.append(7630.95)         #按要求添加新元素
price_index.append(18906.92)  # 将股指收盘点数添加到列表
price_index.append(3442.93)  # 将股指收盘点数添加到列表
price_index.append(22268.09)  # 将股指收盘点数添加到列表
print(price_index)                 #打印添加新元素后的price_index列表


#任务三
name_index = ["道琼斯工业平均指数","富时100指数","标普500指数","恒生指数","日经225指数","上证指数","深证指数"] 
price_index = [41563.08,8376.63,5648.40,17989.07,38647.75,2842.21,8348.48]  # 定义列表price_index                         
 
price_index.remove(38647.75)  #删除"日经225指数"这个元素
                             
 
price_index.insert(6,2674.45)  #添加索引为6的"韩国综合指数"这个元素
print(name_index)  # 输出指数数据
print(price_index)  # 输出价格数据

#任务四
name_index = ["道琼斯工业平均指数","富时100指数","标普500指数","恒生指数","日经225指数","上证指数","深证指数"] 
price_index = [41563.08,8376.63,5648.40,17989.07,38647.75,2842.21,8348.48]  # 定义列表price_index
 
price_index.sort()     #将price_index列表元素由小到大排序
print(price_index)  # 输出价格数据

price_index.reverse()     #将price_index列表元素翻转
print(price_index)  # 输出价格数据

price_index.clear()  #删除price_index列表全部元素(使用clear函数)
print(price_index)  # 输出价格数据

预期输出(本机实际运行结果,具体以平台运行结果为准):

标普500指数
1
['道琼斯工业平均指数', '富时100指数', '标普500指数', '恒生指数', '日经225指数', '上证指数', '深证指数', '法国CAC40指数', '德国DAX指数', '新加坡海峡指数', '台湾加权指数']
[41563.08, 8376.63, 5648.4, 17989.07, 38647.75, 2842.21, 8348.48, 7630.95, 18906.92, 3442.93, 22268.09]
['道琼斯工业平均指数', '富时100指数', '标普500指数', '恒生指数', '日经225指数', '上证指数', '深证指数']
[41563.08, 8376.63, 5648.4, 17989.07, 2842.21, 8348.48, 2674.45]
[2842.21, 5648.4, 8348.48, 8376.63, 17989.07, 38647.75, 41563.08]
[41563.08, 38647.75, 17989.07, 8376.63, 8348.48, 5648.4, 2842.21]
[]

补充说明:任务三中名称与点数不再一一对应

任务三只对price_index执行了remove(38647.75)insert(6, 2674.45),而name_index始终保持7个元素不变。删除”日经225指数”的点数并新增”韩国综合指数”后,price_index仍有7个元素但内容已变,两个列表的同一下标对应的名称与点数因此错位(例如索引4的”日经225指数”已无对应点数)。完整的做法应当同步增删name_index,保持两个列表的一一对应关系:

列表 43.2: 任务三:同步增删name_index保持一一对应
name_index = ["道琼斯工业平均指数","富时100指数","标普500指数","恒生指数","日经225指数","上证指数","深证指数"]
price_index = [41563.08,8376.63,5648.40,17989.07,38647.75,2842.21,8348.48]  # 与name_index一一对应

name_index.remove("日经225指数")  # 同步删除"日经225指数"的名称
price_index.remove(38647.75)  # 同步删除其对应点数
name_index.insert(6, "韩国综合指数")  # 在索引6同步插入"韩国综合指数"
price_index.insert(6, 2674.45)  # 同步插入其对应点数
print(list(zip(name_index, price_index)))  # 名称与点数仍然一一对应
列表 43.3: 列表的基本操作与金融股票管理
# 创建列表:存储券商股票名称
# 方括号[]是列表的字面量语法
# 列表可以包含任意类型的对象,这里存储字符串类型的股票名称
stocks = ['中信证券', '国泰君安', '海通证券', '华泰证券']

# 访问元素:索引从0开始
# stocks[0]访问第一个元素,索引0指向列表的第一个位置
print('第一个:', stocks[0])  # 输出: 中信证券

# 负数索引:-1表示最后一个元素
# 这种语法糖简化了对列表末尾元素的访问
print('最后一个:', stocks[-1])  # 输出: 华泰证券

# 切片操作:[start:end],包含start,不包含end
# stocks[:3]等价于stocks[0:3],获取前3个元素(索引0,1,2)
print('前3个:', stocks[:3])  # 输出: ['中信证券', '国泰君安', '海通证券']

# stocks[1:4]获取索引1到3的元素(不包含索引4)
# 切片操作创建列表的浅拷贝,不会修改原列表
print('第2-4个:', stocks[1:4])  # 输出: ['国泰君安', '海通证券', '华泰证券']

# 修改元素:通过索引直接赋值
# 列表的可变性允许我们原地修改元素,而不需要创建新列表
stocks[1] = '申万宏源'  # 将索引1的元素从'国泰君安'改为'申万宏源'
print('\n修改后:', stocks)  # 输出修改后的完整列表

# 添加元素:append()方法在列表末尾添加元素
# append()的时间复杂度是amortized O(1),非常高效
stocks.append('招商证券')  # 在末尾添加'招商证券'
print('追加后:', stocks)  # 输出: ['中信证券', '申万宏源', '海通证券', '华泰证券', '招商证券']

# 删除元素:remove()方法删除第一个匹配的元素
# remove()需要先查找元素,时间复杂度为O(n)
stocks.remove('海通证券')  # 删除'海通证券'
print('删除后:', stocks)  # 输出: ['中信证券', '申万宏源', '华泰证券', '招商证券']

代码深度解析:

  1. 索引机制的内存模型:

    • Python列表存储的是对象的引用,而非对象本身
    • 每个引用占用8字节(64位系统)
    • 实际的字符串对象存储在堆内存的其他位置
  2. 切片操作的内存行为:

    # 切片创建新列表(浅拷贝)
    sub_list = stocks[1:3]  # 创建新列表,包含对原对象的引用
    
    # 修改原列表不影响切片
    stocks[1] = '新券商'
    # sub_list[1]仍然是'海通证券'
  3. append() vs insert() 性能对比: | 操作 | 时间复杂度 | 说明 | |——|———–|——| | append() | amortized O(1) | 在末尾添加,无需移动其他元素 | | insert(0, x) | O(n) | 在开头添加,需要移动所有元素 | | pop() | O(1) | 弹出末尾元素 | | pop(0) | O(n) | 弹出首元素,需要移动所有元素 |

  4. 金融应用:实时行情更新:

    # 模拟实时价格序列
    prices = []  # 空列表,用于存储价格历史
    
    # append()高效添加新价格
    for new_price in [10.5, 10.6, 10.55, 10.7]:
        prices.append(new_price)
    
    # 计算简单移动平均
    # sum()和len()都是O(1)时间复杂度
    avg_price = sum(prices) / len(prices)
    print(f'平均价格: {avg_price:.2f}')

43.4 列表方法与时间复杂度分析

讨论各方法的时间复杂度之前,先看列表底层是如何实现的——Python列表基于动态数组(Dynamic Array),其设计体现了空间与时间的平衡:

理论背景:动态数组的实现原理

Python列表(List)是基于动态数组(Dynamic Array)实现的顺序数据结构。从计算机科学的角度来看,列表的设计体现了空间与时间的精妙平衡:

  1. 连续内存存储: 列表元素在内存中连续存储,利用局部性原理(Locality Principle),提高CPU缓存命中率
  2. 自动扩容机制: 当空间不足时,列表会自动分配更大的内存块并复制元素,这种策略被称为超额分配(Over-allocation)
  3. amortized O(1): 虽然扩容操作本身是O(n),但由于扩容频率低,分摊到每次操作的平均时间复杂度为O(1)

“分摊复杂度为O(1)”这一结论可以由扩容策略的形式化分析得到:

数学分析:扩容策略的时间复杂度证明

Python列表的扩容采用几何增长策略。假设列表当前容量为N,当需要扩容时,新容量约为:

\[ N_{new} \approx N_{old} \times 1.125 + C \]

其中C是一个常数。这种策略确保了:

  • 扩容次数: 对于插入n个元素,最多需要\(O(\log n)\)次扩容
  • 总复制成本: \(n + n/1.125 + n/1.125^2 + \cdots \approx n \times \frac{1}{1-1/1.125} \approx 9n\)
  • amortized cost: \(\frac{9n}{n} = O(1)\)

补充说明:为什么Python列表扩容系数是1.125?

这个数值是内存与扩容频率之间的取舍:较小的系数(如1.125)超额分配少、内存浪费小,但触发扩容更频繁;较大的系数(如2.0)扩容次数少,但每次一次性多占内存。Java ArrayList 取 1.5、C++ std::vector 常取 2.0,Python 的约 1.125(9/8)是三者中更偏向省内存的选择。

列表 43.4: 常用列表方法及其性能特征
# 创建数值列表,用于演示各种列表方法
# 这个列表包含重复元素,便于演示count()方法
numbers = [3, 1, 4, 1, 5, 9, 2, 6]

# sorted()函数:返回排序后的新列表
# 原列表保持不变,sorted()使用Timsort算法,时间复杂度O(n log n)
# Timsort是归并排序和插入排序的混合算法,针对现实数据优化
numbers_sorted = sorted(numbers)
print('排序:', numbers_sorted)  # 输出: [1, 1, 2, 3, 4, 5, 6, 9]

# reverse()方法:原地反转列表
# 这是一个就地操作,不创建新列表,时间复杂度O(n)
numbers_sorted.reverse()  # 反转为降序
print('反转:', numbers_sorted)  # 输出: [9, 6, 5, 4, 3, 2, 1, 1]

# count()方法:统计元素出现次数
# 需要遍历整个列表,时间复杂度O(n)
print(f'计数(1): {numbers_sorted.count(1)}')  # 输出: 2 (数字1出现了2次)

# sum()函数:计算列表元素和
# 这是Python内置函数,时间复杂度O(n)
print(f'求和: {sum(numbers_sorted)}')  # 输出: 31 (9+6+5+4+3+2+1+1)

# len()函数:获取列表长度
# Python内部维护列表长度信息,时间复杂度O(1)
print(f'长度: {len(numbers_sorted)}')  # 输出: 8

# 列表推导式(List Comprehension):创建新列表的优雅方式
# 语法: [expression for item in iterable]
# 列表推导式比传统for循环更快,因为使用了字节码优化
squares = [x**2 for x in numbers_sorted]  # 计算每个元素的平方
print('平方:', squares)  # 输出: [81, 36, 25, 16, 9, 4, 1, 1]

易混淆概念辨析:sort() vs sorted()

方法 原地修改 返回值 使用场景
list.sort() None 不需要保留原列表,节省内存
sorted(list) 新列表 需要保留原顺序
# sort()方法示例
original = [3, 1, 2]
original.sort()  # 原地修改
print(original)  # [1, 2, 3]
# original变量指向的列表已被修改

# sorted()函数示例
original = [3, 1, 2]
new_list = sorted(original)  # 创建新列表
print(original)  # [3, 1, 2] - 原列表不变
print(new_list)  # [1, 2, 3] - 新列表排序

补充说明:Timsort算法的金融应用优势

Python的Timsort算法特别适合金融时间序列数据:

  1. 自适应:对部分有序数据效率极高(接近O(n))
  2. 稳定排序:相等元素的相对顺序保持不变
  3. 内存优化:对临时空间的需求很小

列表操作时间复杂度完整表:

操作 时间复杂度 说明
lst[i] O(1) 索引访问
lst.append(x) amortized O(1) 末尾追加
lst.insert(i, x) O(n) 任意位置插入
lst.pop() O(1) 弹出末尾
del lst[i] O(n) 删除任意位置
lst.remove(x) O(n) 删除指定值
x in lst O(n) 线性搜索
lst.index(x) O(n) 查找索引
len(lst) O(1) 获取长度
lst.sort() O(n log n) 排序

43.5 金融应用投资组合管理

列表 43.5: 用列表管理投资组合持仓
# 定义持仓股票组合
# 这是一个包含字典的列表,每个字典代表一只股票的持仓信息
# 列表允许我们存储多个股票,字典允许每只股票有多个属性
portfolio = [
    {'code': '600519.SH', 'name': '贵州茅台', 'shares': 100, 'price': 1850.00},
    {'code': '000858.SZ', 'name': '五粮液', 'shares': 200, 'price': 220.50},
    {'code': '600036.SH', 'name': '招商银行', 'shares': 500, 'price': 45.20}
]

# 初始化总投资价值为0
total_value = 0

# 遍历投资组合中的每只股票
# for循环逐个访问列表中的元素(这里是字典)
for stock in portfolio:
    # 计算单只股票的持仓价值
    # stock['shares']获取持股数量
    # stock['price']获取股票价格(注意:原代码中第二项使用了'shares'键,可能是笔误)
    value = stock['shares'] * stock['price']

    # 累加到总投资
    # += 是增量赋值操作符,等价于 total_value = total_value + value
    total_value += value

    # 使用f-string格式化输出
    # stock['name']获取股票名称
    # :,.2f 表示格式化为带千分位的两位小数
    print(f"{stock['name']}: {value:,.2f}元")

# 输出总投资
# \n 是换行符
print(f'\n总投资: {total_value:,.2f}元')

代码深度解析:

  1. 列表+字典的数据结构设计:

    # 这种嵌套结构非常适合表示"实体-属性"关系
    # 列表提供顺序和可变性,字典提供灵活的属性访问
    
    # 等价的面向对象设计(需要先定义类)
    class Stock:
        def __init__(self, code, name, shares, price):
            self.code = code
            self.name = name
            self.shares = shares
            self.price = price
    
    # 对于简单数据结构,列表+字典更轻量
    # 对于复杂行为,面向对象设计更合适
  2. 遍历模式的性能考量:

    # 方式1:直接遍历元素(本例使用)
    for stock in portfolio:
        print(stock['name'])
    
    # 方式2:遍历索引
    for i in range(len(portfolio)):
        print(portfolio[i]['name'])
    
    # 方式1更Pythonic,方式2在需要索引时使用
  3. 计算投资组合权重的扩展:

    # 计算每只股票的权重
    weights = []
    for stock in portfolio:
        value = stock['shares'] * stock['price']
        weight = value / total_value
        weights.append(weight)
        print(f"{stock['name']}: {weight:.2%}")
    
    # 验证权重之和是否为1(或100%)
    print(f'权重总和: {sum(weights):.4f}')  # 应该输出1.0000
  4. 实际应用:持仓分析:

    # 找出持仓价值最高的股票
    max_value = 0
    max_stock = None
    
    for stock in portfolio:
        value = stock['shares'] * stock['price']
        if value > max_value:
            max_value = value
            max_stock = stock
    
    print(f'最大持仓: {max_stock["name"]}, 价值: {max_value:,.2f}元')

列表的内存效率分析:

对于n个元素的列表:

  • 引用数组: n × 8字节(64位系统)
  • 对象开销: 每个对象约56字节(Python对象头)
  • 实际数据: 取决于对象内容

例如,包含1000个整数的列表:

  • 引用数组: 8 KB
  • 整数对象: 56 KB (1000 × 56)
  • 总计: 约64 KB

相比之下,NumPy数组只需约8 KB(紧凑存储),这正是科学计算使用NumPy的原因。

最佳实践总结:

  1. 选择列表的场景:
    • 需要频繁添加/删除元素
    • 元素类型不同
    • 需要保持插入顺序
    • 数据量较小(< 10,000个元素)
  2. 避免列表的场景:
    • 频繁在列表头部插入/删除 → 使用collections.deque
    • 需要快速查找 → 使用字典或集合
    • 大规模数值计算 → 使用NumPy数组
    • 需要频繁拼接字符串 → 使用str.join()
  3. 性能优化技巧:
    • 使用list.append()而非list + [x](后者创建新列表)
    • 使用列表推导式而非for循环
    • 预分配列表大小(如果已知):[None] * n
    • 使用extend()批量添加元素而非循环append()

43.6 本章小结

要点:

  • 列表有序、可变、支持异构元素;正向索引从0开始,负向索引从-1开始
  • 增删查改:append()末尾追加(amortized O(1))、insert(i, x) 定位插入(O(n))、remove(值) 按值删除、index(值) 查索引、clear() 清空
  • sort() 原地排序且返回 None,sorted() 返回新列表;reverse() 原地反转
  • 平台任务三只修改了 price_index,name_index 未同步增删,按下标一一对应的关系因此错位;规范做法是两个平行列表同步增删,再用 zip() 校验
  • “列表套字典”是表示持仓记录等”实体-属性”数据的常用轻量结构

易错点:

  • sort()reverse()clear() 都返回 None,print(price_index.sort()) 打印出来的是 None 而不是排序结果
  • remove() 只删除第一个匹配元素;元素不存在时抛 ValueError
  • insert(6, 2674.45) 是”在索引6处插入”,原索引6及其后的元素整体后移,不是”替换索引6”
  • 边遍历列表边 remove 会跳过元素,应改用列表推导式生成新列表

43.7 动手与思考

以下练习每题附参考答案(默认折叠)。请先独立完成并写下你的判断,再点开对照,最后上机验证。

  1. 概念自测(不看正课):append()insert() 的时间复杂度为何不同?sort()sorted() 有什么区别?平台任务三之后为什么必须讨论”两个列表是否还一一对应”?

    参考答案(点开前请先独立完成)

    解题思路append() 只在末尾追加,无需移动既有元素,均摊 O(1);insert(0, x) 要把原有元素整体后移一位,最坏 O(n)——插入位置越靠前代价越大。sort() 是列表方法、原地排序、返回 None(误写 price = price.sort() 会把变量变成 None);sorted() 是内置函数、返回新列表、原列表不动,且可用于任何可迭代对象。平台任务三只对 price_index 做了 remove()insert()name_index 未同步增删,两个平行列表按下标配对的关系被破坏(下标相同的名称与点数不再指同一指数),所以必须讨论并同步维护。

    回扣主线章:列表方法的系统讲解见第 章节 2 章。

  2. 输出预测:不运行代码,先写出下面代码的输出结果,再上机检验你的判断。

    price = [41563.08, 8376.63, 5648.40, 17989.07]
    price.append(2842.21)
    print(price.index(5648.40))
    price.remove(8376.63)
    print(price)
    s = sorted(price)
    print(price[0])
    print(s[0])

    参考答案(先写下你的预测再点开)

    解题思路append 后列表为 [41563.08, 8376.63, 5648.4, 17989.07, 2842.21](打印时 5648.40 显示为 5648.4,浮点表示如此);price.index(5648.40) 返回首个等值元素的索引 2remove(8376.63) 按值删除该元素,输出 [41563.08, 5648.4, 17989.07, 2842.21]s = sorted(price) 生成升序新列表 [2842.21, 5648.4, 17989.07, 41563.08],但 price 本身未动,故 price[0] 输出 41563.08s[0] 输出 2842.21

    # 验证脚本:原样运行题面代码
    price = [41563.08, 8376.63, 5648.40, 17989.07]  # 四个指数收盘点数
    price.append(2842.21)  # 末尾追加新点数
    print(price.index(5648.40))  # 查找该点数所在索引
    price.remove(8376.63)  # 按值删除元素
    print(price)  # 输出删除后的列表
    s = sorted(price)  # 生成升序新列表,原列表不动
    print(price[0])  # 原列表首元素
    print(s[0])  # 新列表首元素(最小值)

    预期输出(本机 peter 环境实际运行结果,具体以平台运行结果为准):

    2
    [41563.08, 5648.4, 17989.07, 2842.21]
    41563.08
    2842.21

    回扣主线章:列表方法与 sorted() 的对比见第 章节 2 章。

  3. 动手验证:对同一初始列表分别执行 insert(0, '新指数')append('新指数'),输出两次结果并解释新元素位置的差异;再用 zip(name_index, price_index) 输出两个平行列表的配对结果。

    参考答案(点开前请先独立完成)

    解题思路insert(0, '新指数') 把新元素放到索引 0(头部,其余元素整体后移);append('新指数') 放到末尾——插入位置由第一个参数的索引决定。zip(name_index, price_index) 把两个平行列表按下标配对成元组、list() 展开后一目了然;配对成立的前提正是两个列表一一对应、长度相等(长度不等时 zip 按“木桶原理”截到较短的一方)。

    # 验证脚本:头部插入与末尾追加对比,以及平行列表配对
    name_list_head = ['上证指数', '深证指数']  # 初始列表(头部插入用)
    name_list_tail = ['上证指数', '深证指数']  # 初始列表(末尾追加用)
    name_list_head.insert(0, '新指数')  # 在索引0插入,原元素后移
    name_list_tail.append('新指数')  # 追加到末尾
    print(name_list_head)  # 新元素在最前
    print(name_list_tail)  # 新元素在最后
    name_index = ['上证指数', '深证指数', '恒生指数']  # 指数名称列表
    price_index = [3086.55, 9720.85, 17682.00]  # 与名称一一对应的收盘点数
    print(list(zip(name_index, price_index)))  # 按下标配对为元组列表

    预期输出(本机 peter 环境实际运行结果,具体以平台运行结果为准):

    ['新指数', '上证指数', '深证指数']
    ['上证指数', '深证指数', '新指数']
    [('上证指数', 3086.55), ('深证指数', 9720.85), ('恒生指数', 17682.0)]

    回扣主线章insert()append()zip() 的讲解见第 章节 2 章。

  4. 变式任务(平台任务四同型改造):任选五个指数的收盘点数构成列表,依次执行 sort()reverse()clear() 并在每步后输出;然后把其中的升序要求改用 sorted() 实现,说明两种写法在原列表是否被修改上的差别。

    参考答案(点开前请先独立完成)

    解题思路:取五个指数收盘点数 [41563.08, 8376.63, 5648.40, 17989.07, 2842.21](数据同平台任务)。sort() 原地升序、reverse() 原地反转、clear() 原地清空——三步都在原列表上生效,逐步输出可见其演变。改用 sorted() 后生成的是新列表,原列表保持原序不变;即“改自己”(sort(),返回 None)与“留副本”(sorted(),返回新列表)的差别。

    # 变式程序:sort/reverse/clear原地三连,与sorted()生成新列表对照
    close_points = [41563.08, 8376.63, 5648.40, 17989.07, 2842.21]  # 五个指数收盘点数
    close_points.sort()  # 原地升序排序
    print(close_points)  # 输出升序结果
    close_points.reverse()  # 原地反转(升序变降序)
    print(close_points)  # 输出反转结果
    close_points.clear()  # 清空全部元素
    print(close_points)  # 输出空列表
    close_points2 = [41563.08, 8376.63, 5648.40, 17989.07, 2842.21]  # 重新赋值同一组数据
    ascending_list = sorted(close_points2)  # 生成升序新列表,原列表不动
    print('原列表:', close_points2)  # 原列表保持原序
    print('升序新列表:', ascending_list)  # 新列表已排好序

    预期输出(本机 peter 环境实际运行结果,具体以平台运行结果为准):

    [2842.21, 5648.4, 8376.63, 17989.07, 41563.08]
    [41563.08, 17989.07, 8376.63, 5648.4, 2842.21]
    []
    原列表: [41563.08, 8376.63, 5648.4, 17989.07, 2842.21]
    升序新列表: [2842.21, 5648.4, 8376.63, 17989.07, 41563.08]

    注意:以上为本题变式的独立代码;列表 43.1 对应平台任务的原始代码块仍须原样输入教学平台,不要用本变式替换。

    回扣主线章sort()sorted() 的对比见第 章节 2 章。